package com.andova.glcamera.pool

import android.os.HandlerThread
import androidx.annotation.StringDef
import com.andova.egl.EglTaskHThread
import com.andova.egl.EglTextureHThread
import com.andova.egl.HT
import com.andova.glcamera.GlFrameHThread
import org.apache.commons.pool2.BaseKeyedPooledObjectFactory
import org.apache.commons.pool2.DestroyMode
import org.apache.commons.pool2.PooledObject
import org.apache.commons.pool2.impl.DefaultPooledObject
import org.apache.commons.pool2.impl.GenericKeyedObjectPool
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig

const val HT_NAME_EGL_TASK0 = "TaskEglThread0"
const val HT_NAME_EGL_TASK1 = "TaskEglThread1"
const val HT_NAME_EGL_TEXTURE0 = "TextureEglThread0"
const val HT_NAME_EGL_TEXTURE1 = "TextureEglThread1"
const val HT_NAME_CAMERA0_PREVIEW = "Camera0Preview"
const val HT_NAME_CAMERA1_PREVIEW = "Camera1Preview"
const val HT_NAME_FRAME_HANDLER = "GlFrameHandlerThread"
const val HT_NAME_PIPELINE = "PipelineHandlerThread"

@StringDef(
    HT_NAME_EGL_TASK0, HT_NAME_EGL_TEXTURE0,
    HT_NAME_EGL_TASK1, HT_NAME_EGL_TEXTURE1,
    HT_NAME_CAMERA0_PREVIEW, HT_NAME_CAMERA1_PREVIEW,
    HT_NAME_FRAME_HANDLER, HT_NAME_PIPELINE
)
@Retention(AnnotationRetention.SOURCE)
annotation class PoolKey

@Deprecated("")
class HTFactory : BaseKeyedPooledObjectFactory<String, HandlerThread>() {
    override fun wrap(ht: HandlerThread?): PooledObject<HandlerThread> = DefaultPooledObject(ht)
    override fun create(@PoolKey key: String?): HandlerThread = when (key) {
        HT_NAME_EGL_TASK0, HT_NAME_EGL_TASK1 -> EglTaskHThread(key).apply { startHandler() }
        HT_NAME_EGL_TEXTURE0, HT_NAME_EGL_TEXTURE1 -> EglTextureHThread(key).apply { startHandler() }
        HT_NAME_FRAME_HANDLER -> GlFrameHThread.get().apply { start() }
        else -> HandlerThread(key).apply { start() }
    }

    override fun destroyObject(key: String?, p: PooledObject<HandlerThread>?, mode: DestroyMode?) {
        when (key) {
            HT_NAME_EGL_TASK0, HT_NAME_EGL_TASK1 -> (p?.getObject() as? EglTaskHThread)?.quitHandler()
            HT_NAME_EGL_TEXTURE0, HT_NAME_EGL_TEXTURE1 -> (p?.getObject() as? EglTextureHThread)?.quitHandler()
            else -> p?.getObject()?.apply {
                quit()
                join()
            }
        }
    }
}

@Deprecated("")
class HTConfig : GenericKeyedObjectPoolConfig<HandlerThread>() {
    init {
        maxTotal = 8
        maxIdlePerKey = 8
    }
}

@Deprecated("")
class HandlerThreadPool private constructor(factory: HTFactory, config: HTConfig) : GenericKeyedObjectPool<String, HandlerThread>(factory, config) {
    companion object {
        private val sInstance: HandlerThreadPool by lazy { synchronized(HandlerThreadPool::class) { HandlerThreadPool() } }
        fun get(): HandlerThreadPool = sInstance
    }

    constructor() : this(HTFactory(), HTConfig())

    fun borrowPre(cameraId: String): HandlerThread = borrowObject(if (HT_NAME_CAMERA0_PREVIEW.contains(cameraId)) HT_NAME_CAMERA0_PREVIEW else HT_NAME_CAMERA1_PREVIEW)
    fun returnPre(cameraId: String, ht: HandlerThread) = returnObject((if (HT_NAME_CAMERA0_PREVIEW.contains(cameraId)) HT_NAME_CAMERA0_PREVIEW else HT_NAME_CAMERA1_PREVIEW), ht)
    fun destroyPre(cameraId: String) = clear(if (HT_NAME_CAMERA0_PREVIEW.contains(cameraId)) HT_NAME_CAMERA0_PREVIEW else HT_NAME_CAMERA1_PREVIEW)
    fun borrowTex(cameraId: String): HT? = borrowObject(if (HT_NAME_EGL_TEXTURE0.contains(cameraId)) HT_NAME_EGL_TEXTURE0 else HT_NAME_EGL_TEXTURE1) as? HT
    fun returnTex(cameraId: String, ht: HandlerThread?) = returnObject((if (HT_NAME_EGL_TEXTURE0.contains(cameraId)) HT_NAME_EGL_TEXTURE0 else HT_NAME_EGL_TEXTURE1), ht)
    fun destroyTex(cameraId: String) = clear(if (HT_NAME_EGL_TEXTURE0.contains(cameraId)) HT_NAME_EGL_TEXTURE0 else HT_NAME_EGL_TEXTURE1)
    fun borrowTask(cameraId: String): HT? = borrowObject(if (HT_NAME_EGL_TASK0.contains(cameraId)) HT_NAME_EGL_TASK0 else HT_NAME_EGL_TASK1) as? HT
    fun returnTask(cameraId: String, ht: HandlerThread?) = returnObject((if (HT_NAME_EGL_TASK0.contains(cameraId)) HT_NAME_EGL_TASK0 else HT_NAME_EGL_TASK1), ht)
    fun destroyTask(cameraId: String) = clear(if (HT_NAME_EGL_TASK0.contains(cameraId)) HT_NAME_EGL_TASK0 else HT_NAME_EGL_TASK1)
    fun borrowHdr(key: String): HandlerThread = borrowObject(key)
    fun returnHdr(key: String, ht: HandlerThread) = returnObject(key, ht)
    fun destroyHdr(key: String) = clear(key)
}